﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace HexChessBoard
{
    public static class Evaluation//make internal
    {
        // TODO
        // 6: XBox testing
        // 7: split AB processing to separate processors
        // 8: attacked/defended value

        /// <summary>
        /// Glinksi/McCooey file from {0, 0} to {0, 5} -> {5, 0} to {5, 10} -> {10, 0 } to {10, 5}
        /// </summary>
        /// A1 A2 A3 A4 A5 A6
        /// B1 B2 B3 B4 B5 B6 B7
        /// C1 C2 C3 C4 C5 C6 C7 C8
        /// etc
        private static short[] PawnTable = new short[]{
            0,   5,  15,  20,  25, 50,
          -25,  15,  20,  20,  25, 25, 50,
          -15, -10,  15,  20,  20, 25, 25, 50,
            0, -20, -15,  20,  20, 20, 25, 25, 50,
            0,   0, -15, -10,  15, 20, 20, 20, 25, 50,
            0,   0,   0, -20, -15, 15, 20, 20, 25, 30, 50, 
            0,   0, -15, -10,  15, 20, 20, 20, 25, 50,
            0, -20, -15,  20,  20, 20, 25, 25, 50,
          -15, -10,  15,  20,  20, 25, 25, 50,
          -25,  15,  20,  20,  25, 25, 50,
            0,   5,  15,  20,  25, 50,};

        private static short[] KnightTable = new short[]{
            -40, -35, -25, -25, -35, -40,
            -35, -15,  -5,   0,  -5, -15, -35,
            -25,   0,   5,   5,   5,   5,   0, -25,
            -25, -5,   5,  15,  20,  15,   5, -5, -40,
            -35, -5,   5,  20,  40,  40,  20,   5, -5, -25,
            -40, -25, -5,  20,  40,  45,  40,  20, -5, -25, -40, 
            -35, -5,   5,  20,  40,  40,  20,   5, -5, -25,
            -25, -5,   5,  15,  20,  15,   5,   5, -25,
            -25,   0,   5,   5,   5,   5,   0, -25,
            -35, -15,  -5,   0,  -5, -15, -25,
            -40, -35, -25, -25, -25, -40};

        private static short[] BishopTable = new short[]{
            -25, -20, -15, -15, -20, -25,
            -20, -15,  -5,   0,  -5, -15, -20,
            -15,  -5,   5,   5,   5,   5,   0, -15,
            -15,   5,  10,  15,  20,  15,   5,   0, -15,
            -20,  15,  15,  20,  30,  30,  20,   5,   5, -20,
            -25,   5,   5,  25,  35,  35,  35,  25,   5,   5, -25, 
            -20,  15,  15,  20,  30,  30,  20,   5,   5, -20,
            -15,   5,  10,  15,  20,  15,   5,   0, -15,
            -15,  -5,   5,   5,   5,   5,  -5, -15,
            -20, -15,  -5,   0,  -5, -15, -20,
            -25, -20, -15, -15, -20, -25};

        private static short[] KingTableWhite = new short[]{
            -40, -35, -25, -25, -35, -40,
            -35, -15, -5,   0,  -5, -15, -35,
            -25,   0,  5,   5,   5,   5,   0, -25,
            -25, -15,  5,   5,  20,  20,  20, -5, -25,
            -35, -15,  5,  10,  20,  25,  20,   5, -5, -35,
            -40, -25, -5,  10,  20,  25,  20,  10, -5, -25, -40, 
             50, -15,  5,  10,  20,  25,  20,   5, -5, -35,
            -25, -15,  5,   5,  20,  20,  20, -5, -25,
            -25,   0,   5,   5,   5,   5,   0, -25,
            -35, -15,  -5,   0,  -5, -15, -35,
            -40, -35, -25, -25, -25, -40};

        private static short[] KingTableBlack = new short[]{
            -40, -35, -25, -25, -35, -40,
            -35, -15, -5,   0,  -5, -15, -35,
            -25,   0,  5,   5,   5,   5,   0, -25,
            -25, -15,  5,   5,  20,  20,  20, -5, -25,
            -35, -15,  5,  10,  20,  25,  20,   5, -15, -35,
            -40, -25, -5,  10,  20,  25,  20,  10, -15, -25, -40, 
            -45, -15,  5,  10,  20,  25,  20, -10, -15,  50,
            -25, -15,  5,   5,  20,  20,  20, -25, -25,
            -25,   0,   5,   5,   5,   5,   0, -25,
            -35, -15,  -5,   0,  -5, -15, -35,
            -40, -35, -25, -25, -25, -40};

        private static short[] KingTableEndGame = new short[]{
            -40, -35, -25, -25, -35, -40,
            -35, -15, -5, -5, -5, -15, -35,
            -25, -5,   0,   0,   0,   0, -5, -25,
            -25, -5,   0,  15,  20,  15,   0, -5, -25,
            -35, -5,   0,  20,  40,  40,  20,   0, -5, -35,
            -40, -25,   0,  20,  40,  45,  40,  20,   0, -25, -40, 
            -35, -5,   0,  20,  40,  40,  20,   0, -5, -35,
            -25, -5,   0,  15,  20,  15,   0, -5, -25,
            -25, -5,   0,   0,   0,   0, -5, -25,
            -35, -15, -5, -5, -5, -15, -35,
            -40, -35, -25, -25, -35, -40};

        public static int branchCount = 0;

        /// <summary>
        /// Randomize the piece value tables by very small amounts in order to increase complexity.
        /// Call at start of game.
        /// </summary>
        public static void RandomizeArrays()
        {
            Random rand = new Random();
            for (int i = 0; i < 91; i++)
            {
                PawnTable[i] += (short)rand.Next(-2, 2);
                KnightTable[i] += (short)rand.Next(-2, 2);
                BishopTable[i] += (short)rand.Next(-2, 2);
                KingTableBlack[i] += (short)rand.Next(-2, 2);
                KingTableWhite[i] += (short)rand.Next(-2, 2);
                KingTableEndGame[i] += (short)rand.Next(-2, 2);
            }
        }

        private static int ConvertScore(int score, PieceColor sideToScore)
        {
            if (sideToScore == PieceColor.Black)
                return -score;

            return score;
        }

        private static void MoveScore(ref List<Move> possibleMoves)
        {
            int score;
            for (int i = 0; i < possibleMoves.Count; i++)
            {
                score = 0;

                // Set up MVV/LVA by checking the destination
                if (possibleMoves[i].DestTilePiece != PieceType.None)
                {
                    score += (int)possibleMoves[i].DestTilePiece;

                    if ((int)possibleMoves[i].SourceTilePiece < (int)possibleMoves[i].DestTilePiece)
                        score += (int)possibleMoves[i].DestTilePiece - (int)possibleMoves[i].SourceTilePiece;
                }

                if (!possibleMoves[i].SourceTilePieceHasMoved)
                    score += 10;

                possibleMoves[i] = new Move(possibleMoves[i].SourceTilePiece, possibleMoves[i].SourceTileSide, possibleMoves[i].SourceTileIndex, possibleMoves[i].DestTileIndex, possibleMoves[i].DestTilePiece, possibleMoves[i].WasEnPassant, possibleMoves[i].EnPassantIndex, possibleMoves[i].SourceTilePieceHasMoved, possibleMoves[i].SourceTilePieceWasPawnOnStartingTile, possibleMoves[i].BoardRepeatCount, possibleMoves[i].BoardFiftyMoveCount, score);
            }
        }

        private static int WhitePiecesAlive = 0;
        private static int BlackPiecesAlive = 0;
        private static int WhiteKnight = 0;
        private static int WhiteRook = 0;
        private static int WhiteBishop = 0;
        private static int BlackKnight = 0;
        private static int BlackRook = 0;
        private static int BlackBishop = 0;
        private static DateTime startTime;
        private static DateTime endTime;
        private static TimeSpan span;
        private static int timer;

        /// <summary>
        /// Calculates a simple score using only material and mobility, and returns the score already adjusted for the side to score.
        /// Score is calculated in white's favor, and negated when scoring for black.
        /// todo increase complexity
        /// </summary>
        /// <param name="board">The chess board to score.</param>
        private static int BoardScore(Board board)
        {
            int currentScore = 0;

            // Our score is 0 for these values
            if (board.Stalemate || board.FiftyMoveCount > 99 || board.RepeatedMoveCount > 2)
                return 0;

            // max/min the score for any particulars such as mate that are never desirable
            if (board.BlackCheckmate)
                currentScore = short.MaxValue;
            else if (board.WhiteCheckmate)
                currentScore = -short.MaxValue;
            else
            {
                WhitePiecesAlive = 0;
                BlackPiecesAlive = 0;
                WhiteKnight = 0;
                WhiteRook = 0;
                WhiteBishop = 0;
                BlackKnight = 0;
                BlackRook = 0;
                BlackBishop = 0;

                // Score from white's side.
                // 1: get piece values
                // 2: get move/attack values
                // 3: MVD/LVA - most valuable defender, least valuable defender
                // 4: get positional values
                for (int i = 0; i < board.Tiles.Length; i++)
                {
                    if (board.Tiles[i].Piece != PieceType.None)
                    {
                        if (board.Tiles[i].Side == PieceColor.White)
                        {
                            WhitePiecesAlive++;
                            // Do not score the king, as it cannot be captured and it's value is so high that it overrides all other scores
                            currentScore += board.Tiles[i].AvailableMoves.Count;
                            switch (board.Tiles[i].Piece)
                            {
                                case PieceType.Pawn:
                                    currentScore += (int)PieceType.Pawn;
                                    currentScore += PawnTable[i];
                                    // Check isolated pawn
                                    //      Reduce the value of pawns which can't be supported by other pawns
                                    if (board.Variant == GameVariant.Glinsky)
                                    {
                                        // Pawns cannot be supported on the lowest/highest ranks. No hanging pawns.
                                        if (0 < i && i < 5)          // File.A
                                        {
                                            if (board.Tiles[i + 6].Piece != PieceType.Pawn || board.Tiles[i + 6].Side != PieceColor.White)
                                                currentScore -= 12;
                                        }
                                        else if (6 < i && i < 12)    // File.B
                                        {
                                            if ((board.Tiles[i + 7].Piece != PieceType.Pawn || board.Tiles[i + 7].Side != PieceColor.White) &&
                                                (board.Tiles[i - 7].Piece != PieceType.Pawn || board.Tiles[i - 7].Side != PieceColor.White))
                                                currentScore -= 14;
                                        }
                                        else if (13 < i && i < 20)   // File.C
                                        {
                                            if ((board.Tiles[i + 8].Piece != PieceType.Pawn || board.Tiles[i + 8].Side != PieceColor.White) &&
                                                (board.Tiles[i - 8].Piece != PieceType.Pawn || board.Tiles[i - 8].Side != PieceColor.White))
                                                currentScore -= 16;
                                        }
                                        else if (22 < i && i < 27)   // File.D
                                        {
                                            if ((board.Tiles[i + 9].Piece != PieceType.Pawn || board.Tiles[i + 9].Side != PieceColor.White) &&
                                                (board.Tiles[i - 9].Piece != PieceType.Pawn || board.Tiles[i - 9].Side != PieceColor.White))
                                                currentScore -= 18;
                                        }
                                        else if (32 < i && i < 39)   // File.E
                                        {
                                            if ((board.Tiles[i + 10].Piece != PieceType.Pawn || board.Tiles[i + 10].Side != PieceColor.White) &&
                                                (board.Tiles[i - 10].Piece != PieceType.Pawn || board.Tiles[i - 10].Side != PieceColor.White))
                                                currentScore -= 20;
                                        }
                                        else if (43 < i && i < 50)   // File.F
                                        {
                                            if ((board.Tiles[i + 10].Piece != PieceType.Pawn || board.Tiles[i + 10].Side != PieceColor.White) &&
                                                (board.Tiles[i - 11].Piece != PieceType.Pawn || board.Tiles[i - 11].Side != PieceColor.White))
                                                currentScore -= 22;
                                        }
                                        else if (53 < i && i < 60)   // File.G
                                        {
                                            if ((board.Tiles[i + 9].Piece != PieceType.Pawn || board.Tiles[i + 9].Side != PieceColor.White) &&
                                                (board.Tiles[i - 11].Piece != PieceType.Pawn || board.Tiles[i - 11].Side != PieceColor.White))
                                                currentScore -= 20;
                                        }
                                        else if (62 < i && i < 69)   // File.H
                                        {
                                            if ((board.Tiles[i + 8].Piece != PieceType.Pawn || board.Tiles[i + 8].Side != PieceColor.White) &&
                                                (board.Tiles[i - 10].Piece != PieceType.Pawn || board.Tiles[i - 10].Side != PieceColor.White))
                                                currentScore -= 18;
                                        }
                                        else if (70 < i && i < 77)   // File.I
                                        {
                                            if ((board.Tiles[i + 7].Piece != PieceType.Pawn || board.Tiles[i + 7].Side != PieceColor.White) &&
                                                (board.Tiles[i - 9].Piece != PieceType.Pawn || board.Tiles[i - 9].Side != PieceColor.White))
                                                currentScore -= 16;
                                        }
                                        else if (78 < i && i < 84)   // File.K
                                        {
                                            if ((board.Tiles[i + 6].Piece != PieceType.Pawn || board.Tiles[i + 6].Side != PieceColor.White) &&
                                                (board.Tiles[i - 8].Piece != PieceType.Pawn || board.Tiles[i - 8].Side != PieceColor.White))
                                                currentScore -= 14;
                                        }
                                        else if (85 < i && i < 90)   // File.L
                                        {
                                            if (board.Tiles[i - 7].Piece != PieceType.Pawn || board.Tiles[i - 7].Side != PieceColor.White)
                                                currentScore -= 12;
                                        }
                                    }
                                    else if (board.Variant == GameVariant.McCooey)
                                    {
                                        if (0 < i && i < 5)          // File.A
                                        {
                                            if (board.Tiles[i + 5].Piece != PieceType.Pawn || board.Tiles[i + 5].Side != PieceColor.White)
                                                currentScore -= 12;
                                        }
                                        else if (7 < i && i < 12)    // File.B
                                        {
                                            if ((board.Tiles[i + 6].Piece != PieceType.Pawn || board.Tiles[i + 6].Side != PieceColor.White) &&
                                                (board.Tiles[i - 8].Piece != PieceType.Pawn || board.Tiles[i - 8].Side != PieceColor.White))
                                                currentScore -= 14;
                                        }
                                        else if (14 < i && i < 20)   // File.C
                                        {
                                            if ((board.Tiles[i + 7].Piece != PieceType.Pawn || board.Tiles[i + 7].Side != PieceColor.White) &&
                                                (board.Tiles[i - 9].Piece != PieceType.Pawn || board.Tiles[i - 9].Side != PieceColor.White))
                                                currentScore -= 16;
                                        }
                                        else if (23 < i && i < 27)   // File.D
                                        {
                                            if ((board.Tiles[i + 8].Piece != PieceType.Pawn || board.Tiles[i + 8].Side != PieceColor.White) &&
                                                (board.Tiles[i - 10].Piece != PieceType.Pawn || board.Tiles[i - 10].Side != PieceColor.White))
                                                currentScore -= 18;
                                        }
                                        else if (33 < i && i < 39)   // File.E
                                        {
                                            if ((board.Tiles[i + 9].Piece != PieceType.Pawn || board.Tiles[i + 9].Side != PieceColor.White) &&
                                                (board.Tiles[i - 11].Piece != PieceType.Pawn || board.Tiles[i - 11].Side != PieceColor.White))
                                                currentScore -= 20;
                                        }
                                        else if (44 < i && i < 49)   // File.F
                                        {
                                            if ((board.Tiles[i + 9].Piece != PieceType.Pawn || board.Tiles[i + 9].Side != PieceColor.White) &&
                                                (board.Tiles[i - 12].Piece != PieceType.Pawn || board.Tiles[i - 12].Side != PieceColor.White))
                                                currentScore -= 22;
                                        }
                                        else if (54 < i && i < 59)   // File.G
                                        {
                                            if ((board.Tiles[i + 8].Piece != PieceType.Pawn || board.Tiles[i + 8].Side != PieceColor.White) &&
                                                (board.Tiles[i - 12].Piece != PieceType.Pawn || board.Tiles[i - 12].Side != PieceColor.White))
                                                currentScore -= 20;
                                        }
                                        else if (63 < i && i < 68)   // File.H
                                        {
                                            if ((board.Tiles[i + 7].Piece != PieceType.Pawn || board.Tiles[i + 7].Side != PieceColor.White) &&
                                                (board.Tiles[i - 11].Piece != PieceType.Pawn || board.Tiles[i - 11].Side != PieceColor.White))
                                                currentScore -= 18;
                                        }
                                        else if (71 < i && i < 76)   // File.I
                                        {
                                            if ((board.Tiles[i + 6].Piece != PieceType.Pawn || board.Tiles[i + 6].Side != PieceColor.White) &&
                                                (board.Tiles[i - 10].Piece != PieceType.Pawn || board.Tiles[i - 10].Side != PieceColor.White))
                                                currentScore -= 16;
                                        }
                                        else if (79 < i && i < 83)   // File.K
                                        {
                                            if ((board.Tiles[i + 5].Piece != PieceType.Pawn || board.Tiles[i + 5].Side != PieceColor.White) &&
                                                (board.Tiles[i - 9].Piece != PieceType.Pawn || board.Tiles[i - 9].Side != PieceColor.White))
                                                currentScore -= 14;
                                        }
                                        else if (86 < i && i < 90)   // File.L
                                        {
                                            if (board.Tiles[i - 8].Piece != PieceType.Pawn || board.Tiles[i - 8].Side != PieceColor.White)
                                                currentScore -= 12;
                                        }
                                    }
                                    else if (board.Variant == GameVariant.Shafran)
                                    {
                                    }
                                    // Check doubled pawn
                                    //      Reduce the value of doubled/tripled/etc pawns for white
                                    int j = i;
                                    while (j != board.Tiles.Length - 1 && board.Tiles[j + 1].file == board.Tiles[j].file)
                                    {
                                        if (board.Tiles[j + 1].Piece == PieceType.Pawn && board.Tiles[j + 1].Side == PieceColor.White)
                                            currentScore -= 10;
                                        j++;
                                    }
                                    j = i;
                                    while (j != 0 && board.Tiles[j - 1].file == board.Tiles[j].file)
                                    {
                                        if (board.Tiles[j - 1].Piece == PieceType.Pawn && board.Tiles[j - 1].Side == PieceColor.White)
                                            currentScore -= 10;
                                        j--;
                                    }
                                    // check hanging pawn
                                    break;
                                case PieceType.Rook:
                                    currentScore += (int)PieceType.Rook;
                                    currentScore += BishopTable[i];
                                    WhiteRook++; break;
                                case PieceType.Knight:
                                    currentScore += (int)PieceType.Knight;
                                    currentScore += KnightTable[i];
                                    WhiteKnight++; break;
                                case PieceType.Bishop:
                                    currentScore += (int)PieceType.Bishop;
                                    currentScore += BishopTable[i];
                                    WhiteBishop++; break;
                                case PieceType.Queen:
                                    currentScore += (int)PieceType.Queen;
                                    currentScore += BishopTable[i];
                                    // reduce likelihood of queen moving at start of game
                                    if (board.Tiles[i].PieceHasMoved && board.Moves.Count < 20)
                                        currentScore -= 20;
                                    break;
                            }
                        }
                        else
                        {
                            BlackPiecesAlive++;
                            // Do not score the king, as it cannot be captured and it's value is so high that it overrides all other scores
                            currentScore -= (int)board.Tiles[i].AvailableMoves.Count;
                            switch (board.Tiles[i].Piece)
                            {
                                case PieceType.Pawn:
                                    currentScore -= (int)PieceType.Pawn;
                                    currentScore -= PawnTable[90 - i];
                                    // Check isolated pawn
                                    //      Reduce the value of pawns which can't be supported by other pawns
                                    if (board.Variant == GameVariant.Glinsky)
                                    {
                                        // Pawns cannot be supported on the lowest/highest ranks. No hanging pawns.
                                        if (0 < i && i < 5)          // File.A
                                        {
                                            if (board.Tiles[i + 7].Piece != PieceType.Pawn || board.Tiles[i + 7].Side != PieceColor.White)
                                                currentScore -= 12;
                                        }
                                        else if (6 < i && i < 12)    // File.B
                                        {
                                            if ((board.Tiles[i + 8].Piece != PieceType.Pawn || board.Tiles[i + 8].Side != PieceColor.White) &&
                                                (board.Tiles[i - 6].Piece != PieceType.Pawn || board.Tiles[i - 6].Side != PieceColor.White))
                                                currentScore -= 14;
                                        }
                                        else if (13 < i && i < 20)   // File.C
                                        {
                                            if ((board.Tiles[i + 9].Piece != PieceType.Pawn || board.Tiles[i + 9].Side != PieceColor.White) &&
                                                (board.Tiles[i - 7].Piece != PieceType.Pawn || board.Tiles[i - 7].Side != PieceColor.White))
                                                currentScore -= 16;
                                        }
                                        else if (22 < i && i < 27)   // File.D
                                        {
                                            if ((board.Tiles[i + 10].Piece != PieceType.Pawn || board.Tiles[i + 10].Side != PieceColor.White) &&
                                                (board.Tiles[i - 8].Piece != PieceType.Pawn || board.Tiles[i - 8].Side != PieceColor.White))
                                                currentScore -= 18;
                                        }
                                        else if (32 < i && i < 39)   // File.E
                                        {
                                            if ((board.Tiles[i + 11].Piece != PieceType.Pawn || board.Tiles[i + 11].Side != PieceColor.White) &&
                                                (board.Tiles[i - 9].Piece != PieceType.Pawn || board.Tiles[i - 9].Side != PieceColor.White))
                                                currentScore -= 20;
                                        }
                                        else if (43 < i && i < 50)   // File.F
                                        {
                                            if ((board.Tiles[i + 11].Piece != PieceType.Pawn || board.Tiles[i + 11].Side != PieceColor.White) &&
                                                (board.Tiles[i - 10].Piece != PieceType.Pawn || board.Tiles[i - 10].Side != PieceColor.White))
                                                currentScore -= 22;
                                        }
                                        else if (53 < i && i < 60)   // File.G
                                        {
                                            if ((board.Tiles[i + 10].Piece != PieceType.Pawn || board.Tiles[i + 10].Side != PieceColor.White) &&
                                                (board.Tiles[i - 10].Piece != PieceType.Pawn || board.Tiles[i - 10].Side != PieceColor.White))
                                                currentScore -= 20;
                                        }
                                        else if (62 < i && i < 69)   // File.H
                                        {
                                            if ((board.Tiles[i + 9].Piece != PieceType.Pawn || board.Tiles[i + 9].Side != PieceColor.White) &&
                                                (board.Tiles[i - 9].Piece != PieceType.Pawn || board.Tiles[i - 9].Side != PieceColor.White))
                                                currentScore -= 18;
                                        }
                                        else if (70 < i && i < 77)   // File.I
                                        {
                                            if ((board.Tiles[i + 8].Piece != PieceType.Pawn || board.Tiles[i + 8].Side != PieceColor.White) &&
                                                (board.Tiles[i - 8].Piece != PieceType.Pawn || board.Tiles[i - 8].Side != PieceColor.White))
                                                currentScore -= 16;
                                        }
                                        else if (78 < i && i < 84)   // File.K
                                        {
                                            if ((board.Tiles[i + 7].Piece != PieceType.Pawn || board.Tiles[i + 7].Side != PieceColor.White) &&
                                                (board.Tiles[i - 7].Piece != PieceType.Pawn || board.Tiles[i - 7].Side != PieceColor.White))
                                                currentScore -= 14;
                                        }
                                        else if (85 < i && i < 90)   // File.L
                                        {
                                            if (board.Tiles[i - 6].Piece != PieceType.Pawn || board.Tiles[i - 6].Side != PieceColor.White)
                                                currentScore -= 12;
                                        }
                                    }
                                    else if (board.Variant == GameVariant.McCooey)
                                    {
                                        if (0 < i && i < 5)          // File.A
                                        {
                                            if (board.Tiles[i + 8].Piece != PieceType.Pawn || board.Tiles[i + 8].Side != PieceColor.White)
                                                currentScore -= 12;
                                        }
                                        else if (7 < i && i < 12)    // File.B
                                        {
                                            if ((board.Tiles[i + 9].Piece != PieceType.Pawn || board.Tiles[i + 9].Side != PieceColor.White) &&
                                                (board.Tiles[i - 5].Piece != PieceType.Pawn || board.Tiles[i - 5].Side != PieceColor.White))
                                                currentScore -= 14;
                                        }
                                        else if (14 < i && i < 20)   // File.C
                                        {
                                            if ((board.Tiles[i + 10].Piece != PieceType.Pawn || board.Tiles[i + 10].Side != PieceColor.White) &&
                                                (board.Tiles[i - 6].Piece != PieceType.Pawn || board.Tiles[i - 6].Side != PieceColor.White))
                                                currentScore -= 16;
                                        }
                                        else if (23 < i && i < 27)   // File.D
                                        {
                                            if ((board.Tiles[i + 11].Piece != PieceType.Pawn || board.Tiles[i + 11].Side != PieceColor.White) &&
                                                (board.Tiles[i - 7].Piece != PieceType.Pawn || board.Tiles[i - 7].Side != PieceColor.White))
                                                currentScore -= 18;
                                        }
                                        else if (33 < i && i < 39)   // File.E
                                        {
                                            if ((board.Tiles[i + 12].Piece != PieceType.Pawn || board.Tiles[i + 12].Side != PieceColor.White) &&
                                                (board.Tiles[i - 8].Piece != PieceType.Pawn || board.Tiles[i - 8].Side != PieceColor.White))
                                                currentScore -= 20;
                                        }
                                        else if (44 < i && i < 49)   // File.F
                                        {
                                            if ((board.Tiles[i + 12].Piece != PieceType.Pawn || board.Tiles[i + 12].Side != PieceColor.White) &&
                                                (board.Tiles[i - 9].Piece != PieceType.Pawn || board.Tiles[i - 9].Side != PieceColor.White))
                                                currentScore -= 22;
                                        }
                                        else if (54 < i && i < 59)   // File.G
                                        {
                                            if ((board.Tiles[i + 11].Piece != PieceType.Pawn || board.Tiles[i + 11].Side != PieceColor.White) &&
                                                (board.Tiles[i - 9].Piece != PieceType.Pawn || board.Tiles[i - 9].Side != PieceColor.White))
                                                currentScore -= 20;
                                        }
                                        else if (63 < i && i < 68)   // File.H
                                        {
                                            if ((board.Tiles[i + 10].Piece != PieceType.Pawn || board.Tiles[i + 10].Side != PieceColor.White) &&
                                                (board.Tiles[i - 8].Piece != PieceType.Pawn || board.Tiles[i - 8].Side != PieceColor.White))
                                                currentScore -= 18;
                                        }
                                        else if (71 < i && i < 76)   // File.I
                                        {
                                            if ((board.Tiles[i + 9].Piece != PieceType.Pawn || board.Tiles[i + 9].Side != PieceColor.White) &&
                                                (board.Tiles[i - 7].Piece != PieceType.Pawn || board.Tiles[i - 7].Side != PieceColor.White))
                                                currentScore -= 16;
                                        }
                                        else if (79 < i && i < 83)   // File.K
                                        {
                                            if ((board.Tiles[i + 8].Piece != PieceType.Pawn || board.Tiles[i + 8].Side != PieceColor.White) &&
                                                (board.Tiles[i - 6].Piece != PieceType.Pawn || board.Tiles[i - 6].Side != PieceColor.White))
                                                currentScore -= 14;
                                        }
                                        else if (86 < i && i < 90)   // File.L
                                        {
                                            if (board.Tiles[i - 5].Piece != PieceType.Pawn || board.Tiles[i - 5].Side != PieceColor.White)
                                                currentScore -= 12;
                                        }
                                    }
                                    else if (board.Variant == GameVariant.Shafran)
                                    {
                                    }
                                    // Check doubled pawn
                                    //      Increase the value of doubled/tripled/etc pawns for black (Same as reducing the score, due to inversion)
                                    int j = i;
                                    while (j != board.Tiles.Length - 1 && board.Tiles[j + 1].file == board.Tiles[j].file)
                                    {
                                        if (board.Tiles[j + 1].Piece == PieceType.Pawn && board.Tiles[j + 1].Side == PieceColor.Black)
                                            currentScore += 10;
                                        j++;
                                    }
                                    j = i;
                                    while (j != 0 && board.Tiles[j - 1].file == board.Tiles[j].file)
                                    {
                                        if (board.Tiles[j - 1].Piece == PieceType.Pawn && board.Tiles[j - 1].Side == PieceColor.Black)
                                            currentScore += 10;
                                        j--;
                                    }
                                // check hanging pawn
                                break;
                                case PieceType.Rook:
                                currentScore -= (int)PieceType.Rook;
                                    currentScore -= BishopTable[90 - i];
                                    BlackRook++; break;
                                case PieceType.Knight:
                                    currentScore -= (int)PieceType.Knight;
                                    currentScore -= KnightTable[90 - i];
                                    BlackKnight++; break;
                                case PieceType.Bishop:
                                    currentScore -= (int)PieceType.Bishop;
                                    currentScore -= BishopTable[90 - i];
                                    BlackBishop++; break;
                                case PieceType.Queen:
                                    currentScore -= (int)PieceType.Queen;
                                    currentScore -= BishopTable[90 - i];
                                    // reduce likelihood of queen moving at start of game
                                    if (board.Tiles[i].PieceHasMoved && board.Moves.Count < 20)
                                        currentScore += 20;
                                    break;
                            }
                        }
                    }
                }

                if (WhiteBishop == 3)
                    currentScore += 40;
                if (WhiteRook == 2)
                    currentScore += 30;
                if (WhiteKnight == 2)
                    currentScore += 15;
                if (BlackBishop == 3)
                    currentScore -= 40;
                if (BlackRook == 2)
                    currentScore -= 30;
                if (BlackKnight == 2)
                    currentScore -= 15;

                // Adjust score for large factors
                if (board.BlackCheck)
                    currentScore += 35;
                if (board.WhiteCheck)
                    currentScore -= 35;

                if (WhitePiecesAlive < 8)
                {
                    currentScore += KingTableEndGame[board.WhiteKing];
                    if (board.WhiteCheck)
                        currentScore -= 10;
                }
                else if (board.Variant != GameVariant.Shafran)          // Just ignore for Shafran, rather than create new tables
                    currentScore += KingTableWhite[board.WhiteKing];

                if (BlackPiecesAlive < 8)
                {
                    currentScore -= KingTableEndGame[90 - board.BlackKing];
                    if (board.BlackCheck)
                        currentScore += 10;
                }
                else if (board.Variant != GameVariant.Shafran)          // Just ignore for Shafran, rather than create new tables
                    currentScore -= KingTableBlack[90 - board.BlackKing];
            }

            return currentScore;
        }

        /// <summary>
        /// Get possible moves outside of ABRoot, in order to break them into chunks for parallel processing.
        /// </summary>
        /// <param name="board"></param>
        /// <returns></returns>
        public static List<Move> GetPossibleMoves(Board board, ref int depth)
        {
            // Get the scoring sides available moves. This allows AlphaBeta to prune at the earliest branches possible
            List<Move> possibleMoves = new List<Move>();
            for (int i = 0; i < board.Tiles.Length; i++)
            {
                if (board.Tiles[i].Piece != PieceType.None)
                {
                    if (board.Tiles[i].Side == board.CurrentTurn)
                    {
                        for (int y = 0; y < board.Tiles[i].AvailableMoves.Count; y++)
                            possibleMoves.Add(new Move(board.Tiles[i].Piece, board.Tiles[i].Side, board.Tiles[i].IndexInArray, board.Tiles[i].AvailableMoves[y].IndexInArray, board.Tiles[i].AvailableMoves[y].Piece, board.Tiles[i].WasEnPassant, board.Tiles[i].EnPassantIndex, board.Tiles[i].PieceHasMoved, board.Tiles[i].PieceWasPawnOnStartingTile, board.RepeatedMoveCount, board.FiftyMoveCount, 0));
                    }
                }
            }
            if (possibleMoves.Count < 10)
                depth++;
            if (possibleMoves.Count < 5)
                depth++;

            // Score the moves quickly for sorting, using MVV/LVA and a few other pieces
            MoveScore(ref possibleMoves);

            // Sort tiles, putting all captures first in MVV/LVA order, then moves in order of the piece.
            possibleMoves.Sort(SortMoves);

            return possibleMoves;
        }

        //public static Move MiniMaxRoot(Board board, int depth)
        //{
        //    int bestValue;
        //    if (board.CurrentTurn == PieceColor.White)
        //        bestValue = -10000000;
        //    else
        //        bestValue = 10000000;

        //    // Get the scoring sides available moves. This allows AlphaBeta to prune at the earliest branches possible
        //    // todo construct add board level, dont reconstruct here
        //    List<Move> possibleMoves = new List<Move>();
        //    for (int i = 0; i < 11; i++)
        //    {
        //        for (int j = 0; j < 11; j++)
        //        {
        //            if (board.Tiles[i, j] != null && board.Tiles[i, j].Piece != PieceType.None && board.Tiles[i, j].Side == board.CurrentTurn)
        //            {
        //                for (int y = 0; y < board.Tiles[i, j].AvailableMoves.Count; y++)
        //                    possibleMoves.Add(new Move(board.Tiles[i, j].Piece, board.Tiles[i, j].Side, board.Tiles[i, j].file, board.Tiles[i, j].rank, board.Tiles[i, j].AvailableMoves[y].file, board.Tiles[i, j].AvailableMoves[y].rank, board.Tiles[i, j].AvailableMoves[y].Piece, board.Tiles[i, j].WasEnPassant, board.Tiles[i, j].EnPassantTileFile, board.Tiles[i, j].EnPassantTileRank, board.Tiles[i, j].PieceHasMoved, board.Tiles[i, j].PieceWasPawnOnStartingTile, board.RepeatedMoveCount, board.FiftyMoveCount, 0));
        //            }
        //        }
        //    }

        //    // Score the moves quickly for sorting, using MVV/LVA and a few other pieces
        //    MoveScore(ref possibleMoves);

        //    // Sort tiles, putting all captures first in MVV/LVA order, then moves in order of the piece.
        //    possibleMoves.Sort(SortMoves);

        //    Move bestMove = new Move();

        //    // Inspect all possible moves for the current player
        //    for (int i = 0; i < possibleMoves.Count; i++)
        //    {
        //        // increment how many possible moves we've encountered
        //        branchCount++;
        //        // Move a piece on the newly duplicated board for the current player
        //        BoardSupport.MovePiece(ref board, ref board.Tiles[(int)possibleMoves[i].SourceTileFile, (int)possibleMoves[i].SourceTileRank], ref board.Tiles[(int)possibleMoves[i].DestTileFile, (int)possibleMoves[i].DestTileRank]);
        //        // End the turn and get the peices for the opposing side to pass to the next AlphaBeta call.
        //        BoardSupport.EndTurn(ref board, PieceType.Queen);
        //        // We do not need to check if we made a move that left us in check, because we take care of that in GetAvailableMoves

        //        // Iterate deeper into the tree until we can score it
        //        int v = MiniMax(board, depth - 1);

        //        // undo the latest move for the board, resetting the board to the previous players turn, which changed in "EndTurn"
        //        //b.CurrentTurn = (board.CurrentTurn == PieceColor.White ? PieceColor.Black : PieceColor.White);
        //        BoardSupport.MovePieceUndoLatest(ref board);
        //        board.CurrentTurn = (board.CurrentTurn == PieceColor.White ? PieceColor.Black : PieceColor.White);

        //        if (board.CurrentTurn == PieceColor.White)
        //        {
        //            //bestValue = Math.Max(v, bestValue);
        //            if (v > bestValue)
        //            {
        //                bestValue = v;
        //                bestMove = possibleMoves[i];
        //            }
        //        }
        //        else
        //        {
        //            //bestValue = Math.Min(v, bestValue);
        //            if (v < bestValue)
        //            {
        //                bestValue = v;
        //                bestMove = possibleMoves[i];
        //            }
        //        }
        //    }

        //    return bestMove;
        //}

        //private static int MiniMax(Board board, int depth)
        //{
        //    if (depth == 0)
        //        return BoardScore(board);

        //    int bestValue;
        //    if (board.CurrentTurn == PieceColor.White)
        //        bestValue = -10000000;
        //    else
        //        bestValue = 10000000;

        //    // Get the scoring sides available moves. This allows AlphaBeta to prune at the earliest branches possible
        //    // todo construct add board level, dont reconstruct here
        //    List<Move> possibleMoves = new List<Move>();
        //    for (int i = 0; i < 11; i++)
        //    {
        //        for (int j = 0; j < 11; j++)
        //        {
        //            if (board.Tiles[i, j] != null && board.Tiles[i, j].Piece != PieceType.None && board.Tiles[i, j].Side == board.CurrentTurn)
        //            {
        //                for (int y = 0; y < board.Tiles[i, j].AvailableMoves.Count; y++)
        //                    possibleMoves.Add(new Move(board.Tiles[i, j].Piece, board.Tiles[i, j].Side, board.Tiles[i, j].file, board.Tiles[i, j].rank, board.Tiles[i, j].AvailableMoves[y].file, board.Tiles[i, j].AvailableMoves[y].rank, board.Tiles[i, j].AvailableMoves[y].Piece, board.Tiles[i, j].WasEnPassant, board.Tiles[i, j].EnPassantTileFile, board.Tiles[i, j].EnPassantTileRank, board.Tiles[i, j].PieceHasMoved, board.Tiles[i, j].PieceWasPawnOnStartingTile, board.RepeatedMoveCount, board.FiftyMoveCount, 0));
        //            }
        //        }
        //    }

        //    // Score the moves quickly for sorting, using MVV/LVA and a few other pieces
        //    MoveScore(ref possibleMoves);

        //    // Sort tiles, putting all captures first in MVV/LVA order, then moves in order of the piece.
        //    possibleMoves.Sort(SortMoves);

        //    // Inspect all possible moves for the current player
        //    for (int i = 0; i < possibleMoves.Count; i++)
        //    {
        //        // increment how many possible moves we've encountered
        //        branchCount++;
        //        // Move a piece on the newly duplicated board for the current player
        //        BoardSupport.MovePiece(ref board, ref board.Tiles[(int)possibleMoves[i].SourceTileFile, (int)possibleMoves[i].SourceTileRank], ref board.Tiles[(int)possibleMoves[i].DestTileFile, (int)possibleMoves[i].DestTileRank]);
        //        // End the turn and get the peices for the opposing side to pass to the next AlphaBeta call.
        //        BoardSupport.EndTurn(ref board, PieceType.Queen);
        //        // We do not need to check if we made a move that left us in check, because we take care of that in GetAvailableMoves

        //        // Iterate deeper into the tree until we can score it
        //        int v = MiniMax(board, depth - 1);

        //        // undo the latest move for the board, resetting the board to the previous players turn, which changed in "EndTurn"
        //        //b.CurrentTurn = (board.CurrentTurn == PieceColor.White ? PieceColor.Black : PieceColor.White);
        //        BoardSupport.MovePieceUndoLatest(ref board);
        //        board.CurrentTurn = (board.CurrentTurn == PieceColor.White ? PieceColor.Black : PieceColor.White);

        //        if (board.CurrentTurn == PieceColor.White)
        //            bestValue = Math.Max(v, bestValue);
        //        else
        //            bestValue = Math.Min(v, bestValue);
        //    }

        //    return bestValue;
        //}

        //public static Move NegaMaxRoot(Board board, PieceColor sideToScore, int depth)
        //{
        //    int max = -10000000;

        //    // Get the scoring sides available moves. This allows AlphaBeta to prune at the earliest branches possible
        //    // todo construct add board level, dont reconstruct here
        //    List<Move> possibleMoves = new List<Move>();
        //    for (int i = 0; i < 11; i++)
        //    {
        //        for (int j = 0; j < 11; j++)
        //        {
        //            if (board.Tiles[i, j] != null && board.Tiles[i, j].Piece != PieceType.None && board.Tiles[i, j].Side == board.CurrentTurn)
        //            {
        //                for (int y = 0; y < board.Tiles[i, j].AvailableMoves.Count; y++)
        //                    possibleMoves.Add(new Move(board.Tiles[i, j].Piece, board.Tiles[i, j].Side, board.Tiles[i, j].file, board.Tiles[i, j].rank, board.Tiles[i, j].AvailableMoves[y].file, board.Tiles[i, j].AvailableMoves[y].rank, board.Tiles[i, j].AvailableMoves[y].Piece, board.Tiles[i, j].WasEnPassant, board.Tiles[i, j].EnPassantTileFile, board.Tiles[i, j].EnPassantTileRank, board.Tiles[i, j].PieceHasMoved, board.Tiles[i, j].PieceWasPawnOnStartingTile, board.RepeatedMoveCount, board.FiftyMoveCount, 0));
        //            }
        //        }
        //    }

        //    // Score the moves quickly for sorting, using MVV/LVA and a few other pieces
        //    MoveScore(ref possibleMoves);

        //    // Sort tiles, putting all captures first in MVV/LVA order, then moves in order of the piece.
        //    possibleMoves.Sort(SortMoves);

        //    Move bestMove = new Move();

        //    // Inspect all possible moves for the current player
        //    for (int i = 0; i < possibleMoves.Count; i++)
        //    {
        //        // increment how many possible moves we've encountered
        //        branchCount++;
        //        // Move a piece on the newly duplicated board for the current player
        //        BoardSupport.MovePiece(ref board, ref board.Tiles[(int)possibleMoves[i].SourceTileFile, (int)possibleMoves[i].SourceTileRank], ref board.Tiles[(int)possibleMoves[i].DestTileFile, (int)possibleMoves[i].DestTileRank]);
        //        // End the turn and get the peices for the opposing side to pass to the next AlphaBeta call.
        //        BoardSupport.EndTurn(ref board, PieceType.Queen);
        //        // We do not need to check if we made a move that left us in check, because we take care of that in GetAvailableMoves

        //        // Iterate deeper into the tree until we can score it
        //        //sideToScore = (sideToScore == PieceColor.White ? PieceColor.Black : PieceColor.White);
        //        int v = -NegaMax(board, board.CurrentTurn, depth - 1);

        //        if (v > max)
        //        {
        //            max = v;
        //            bestMove = board.Moves[board.Moves.Count - 1];
        //        }

        //        // undo the latest move for the board, resetting the board to the previous players turn, which changed in "EndTurn"
        //        //b.CurrentTurn = (board.CurrentTurn == PieceColor.White ? PieceColor.Black : PieceColor.White);
        //        BoardSupport.MovePieceUndoLatest(ref board);
        //        board.CurrentTurn = (board.CurrentTurn == PieceColor.White ? PieceColor.Black : PieceColor.White);
        //    }

        //    return bestMove;
        //}

        //private static int NegaMax(Board board, PieceColor sideToScore, int depth)
        //{
        //    if (depth == 0)
        //        return ConvertScore(BoardScore(board), board.CurrentTurn);

        //    int max = -10000000;

        //    // Get the scoring sides available moves. This allows AlphaBeta to prune at the earliest branches possible
        //    // todo construct add board level, dont reconstruct here
        //    List<Move> possibleMoves = new List<Move>();
        //    for (int i = 0; i < 11; i++)
        //    {
        //        for (int j = 0; j < 11; j++)
        //        {
        //            if (board.Tiles[i, j] != null && board.Tiles[i, j].Piece != PieceType.None && board.Tiles[i, j].Side == board.CurrentTurn)
        //            {
        //                for (int y = 0; y < board.Tiles[i, j].AvailableMoves.Count; y++)
        //                    possibleMoves.Add(new Move(board.Tiles[i, j].Piece, board.Tiles[i, j].Side, board.Tiles[i, j].file, board.Tiles[i, j].rank, board.Tiles[i, j].AvailableMoves[y].file, board.Tiles[i, j].AvailableMoves[y].rank, board.Tiles[i, j].AvailableMoves[y].Piece, board.Tiles[i, j].WasEnPassant, board.Tiles[i, j].EnPassantTileFile, board.Tiles[i, j].EnPassantTileRank, board.Tiles[i, j].PieceHasMoved, board.Tiles[i, j].PieceWasPawnOnStartingTile, board.RepeatedMoveCount, board.FiftyMoveCount, 0));
        //            }
        //        }
        //    }

        //    // Score the moves quickly for sorting, using MVV/LVA and a few other pieces
        //    MoveScore(ref possibleMoves);

        //    // Sort tiles, putting all captures first in MVV/LVA order, then moves in order of the piece.
        //    possibleMoves.Sort(SortMoves);

        //    // Inspect all possible moves for the current player
        //    for (int i = 0; i < possibleMoves.Count; i++)
        //    {
        //        // increment how many possible moves we've encountered
        //        branchCount++;
        //        // Move a piece on the newly duplicated board for the current player
        //        BoardSupport.MovePiece(ref board, ref board.Tiles[(int)possibleMoves[i].SourceTileFile, (int)possibleMoves[i].SourceTileRank], ref board.Tiles[(int)possibleMoves[i].DestTileFile, (int)possibleMoves[i].DestTileRank]);
        //        // End the turn and get the peices for the opposing side to pass to the next AlphaBeta call.
        //        BoardSupport.EndTurn(ref board, PieceType.Queen);
        //        // We do not need to check if we made a move that left us in check, because we take care of that in GetAvailableMoves

        //        // Iterate deeper into the tree until we can score it
        //        //sideToScore = (sideToScore == PieceColor.White ? PieceColor.Black : PieceColor.White);
        //        int v = -NegaMax(board, sideToScore, depth - 1);

        //        if (v > max)
        //            max = v;

        //        // undo the latest move for the board, resetting the board to the previous players turn, which changed in "EndTurn"
        //        //b.CurrentTurn = (board.CurrentTurn == PieceColor.White ? PieceColor.Black : PieceColor.White);
        //        BoardSupport.MovePieceUndoLatest(ref board);
        //        board.CurrentTurn = (board.CurrentTurn == PieceColor.White ? PieceColor.Black : PieceColor.White);
        //    }

        //    return max;
        //}

        // todo when checked/stalemated, sometimes no black move
        public static Move AlphaBetaRoot(Board board, int depth, List<Move> possibleMoves)
        {
            branchCount = 0;

            //todo create list of resutls boards, sort, etc, make an alpha beta root.
            int alpha = -10000000;//arbitrarily low
            const int beta = 10000000;//make const, arbitrarily high
            timer = (int)board.difficulty * 5;   // the length allowed for search is 5 seconds times the difficulty integer value

            // Duplicate the board
            Move bestMove = new Move();

            // exist with the best move within the time span
            startTime = System.DateTime.Now;

            // Inspect all possible moves for the current player
            for (int i = 0; i < possibleMoves.Count; i++)
            {
                // increment how many possible moves we've encountered
                branchCount++;

                // Move a piece on the newly duplicated board for the current player
                BoardSupport.MovePiece(ref board, ref board.Tiles[possibleMoves[i].SourceTileIndex], ref board.Tiles[possibleMoves[i].DestTileIndex]);
                // End the turn and get the peices for the opposing side to pass to the next AlphaBeta call.
                BoardSupport.EndTurn(ref board, PieceType.Queen);
                // We do not need to check if we made a move that left us in check, because we take care of that in GetAvailableMoves

                // Iterate deeper into the tree until we can score it
                int v = -AlphaBeta(board, depth - 1, -beta, -alpha);

                // better move found, keep looking.
                //if (v >= beta)
                //    break;    //beta cutoff, look no further in this loop of moves.
                if (v > alpha)
                {
                    alpha = v;
                    // We grab the top most move
                    bestMove = board.Moves[board.Moves.Count - 1];
                    bestMove.Score = alpha;
                }

                BoardSupport.MovePieceUndoLatest(ref board);
                board.CurrentTurn = (board.CurrentTurn == PieceColor.White ? PieceColor.Black : PieceColor.White);  // undo the turn change done in EndTurn

                // check if we're taking too long
                endTime = System.DateTime.Now;
                span = endTime.Subtract(startTime);
                if (span.Seconds > timer)
                    return bestMove;
            }

            // todo check if move is null, i.e. we didn't find anything...
            return bestMove;
        }

        private static int AlphaBeta(Board board, int depth, int alpha, int beta)
        {
            if (depth == 0)                                         // ONLY WHEN t the bottom of the tree, determine the score
                return ConvertScore(BoardScore(board), board.CurrentTurn);          // Score the board from white's perspective then negate if root is black...

            // calling this twice? or even three times? construct, kingincheck, etc
            // todo if mate/check/stalemate and return values

            // Get the scoring sides available moves. This allows AlphaBeta to prune at the earliest branches possible
            // todo construct add board level, dont reconstruct here, high garbage collection. fix root too.
            List<Move> possibleMoves = new List<Move>();
            for (int i = 0; i < board.Tiles.Length; i++)
            {
                if (board.Tiles[i] != null && board.Tiles[i].Piece != PieceType.None && board.Tiles[i].Side == board.CurrentTurn)
                {
                    for (int y = 0; y < board.Tiles[i].AvailableMoves.Count; y++)
                        possibleMoves.Add(new Move(board.Tiles[i].Piece, board.Tiles[i].Side, board.Tiles[i].IndexInArray, board.Tiles[i].AvailableMoves[y].IndexInArray, board.Tiles[i].AvailableMoves[y].Piece, board.Tiles[i].WasEnPassant, board.Tiles[i].EnPassantIndex, board.Tiles[i].PieceHasMoved, board.Tiles[i].PieceWasPawnOnStartingTile, board.RepeatedMoveCount, board.FiftyMoveCount, 0));
                }
            }

            // Score the moves quickly for sorting, using MVV/LVA and a few other pieces
            MoveScore(ref possibleMoves);

            // Sort tiles, putting all captures first in MVV/LVA order, then moves in order of the piece.
            possibleMoves.Sort(SortMoves);

            // Inspect all possible moves for the current player
            for (int i = 0; i < possibleMoves.Count; i++)
            {
                // increment how many possible moves we've encountered
                branchCount++;
                // Move a piece on the newly duplicated board for the current player
                BoardSupport.MovePiece(ref board, ref board.Tiles[possibleMoves[i].SourceTileIndex], ref board.Tiles[possibleMoves[i].DestTileIndex]);
                // End the turn and get the peices for the opposing side to pass to the next AlphaBeta call.
                BoardSupport.EndTurn(ref board, PieceType.Queen);
                // We do not need to check if we made a move that left us in check, because we take care of that in GetAvailableMoves

                // Iterate deeper into the tree until we can score it
                int v = -AlphaBeta(board, depth - 1, -beta, -alpha);

                // undo the latest move for the board, resetting the board to the previous players turn, which changed in "EndTurn"
                BoardSupport.MovePieceUndoLatest(ref board);
                board.CurrentTurn = (board.CurrentTurn == PieceColor.White ? PieceColor.Black : PieceColor.White);// undo the turn change done in EndTurn

                if (v >= beta)
                    return beta;    //beta cutoff, look no further in this loop of moves.
                if (v > alpha)
                    alpha = v;      // better move found, keep looking.

                // check if we're taking too long
                endTime = System.DateTime.Now;
                span = endTime.Subtract(startTime);
                if (span.Seconds > (timer + 5))
                    return alpha;   // We would exit out by beta earlier
            }

            return alpha;
        }

        private static int SortMoves(Move s2, Move s1)
        {
            return (s1.Score).CompareTo(s2.Score);
        }
    }
}
